import CryptoJS from 'crypto-js';
import {default as swal} from 'sweetalert2';

jQuery.noConflict();

(function($, PLUGIN_ID) {
  'use strict';

  const message = {
    'en': {
      'msg_tableTitle_fileName': 'FileName',
      'msg_tableTitle_fileSize': 'Size',
      'msg_tableTitle_fileDate': 'Date',
      'msg_btn_download': 'Download',
      'msg_btn_imageViewer': 'Image Viewer',
      'msg_btn_delete': 'Delete',
      'msg_alert_delete_title': 'Do you want to delete this file?',
      'msg_alert_delete_text': 'You can not revert it!',
      'msg_alert_delete_confirm': 'Yes, delete it!',
      'msg_alert_delete_cancel': 'Cancel',
      'msg_uploading': 'File uploading!',
      'msg_upload_success': 'Finished uploading!',
      'msg_upload_failed': 'Upload failed！',
      'msg_download_error': 'Error downloading or file does not exist!',
      'msg_directory_error': 'Open directory error or directory does not exist!'
    },
    'zh': {
      'msg_tableTitle_fileName': '文件名',
      'msg_tableTitle_fileSize': '文件大小',
      'msg_tableTitle_fileDate': '文件日期',
      'msg_btn_download': '下载',
      'msg_btn_imageViewer': '图片预览',
      'msg_btn_delete': '删除',
      'msg_alert_delete_title': '您想删除这个文件吗？',
      'msg_alert_delete_text': '您将无法恢复这个文件!',
      'msg_alert_delete_confirm': '是，删除它!',
      'msg_alert_delete_cancel': '取消',
      'msg_uploading': '文件上传中!',
      'msg_upload_success': '上传完毕！',
      'msg_upload_failed': '上传失败！',
      'msg_download_error': '下载出错或文件不存在！',
      'msg_directory_error': '打开目录错误或目录不存在！'
    }
  };

  const lang = kintone.getLoginUser().language;
  const i18n = (lang in message) ? message[lang] : message['zh'];
  const attachment = new kintoneUIComponent.Attachment();

  let config;

  const validateConfig = () => {
    config = kintone.plugin.app.getConfig(PLUGIN_ID);
    return config !== null;
  };

  if (!validateConfig()) {
    return;
  }

  const serviceName = config.serviceName;
  const operatorName = config.operatorName;
  const operatorPassword = config.operatorPassword;
  const now = new Date().toUTCString();

  const getSignHeader = (operator, method, path, password, date) => {
    let value = method + '&' + path + '&' + date;
    let auth = createHmacsha1(createMd5(password), value);
    return 'UPYUN ' + operator + ':' + auth;
  };

  const createMd5 = (value) => {
    return CryptoJS.MD5(value).toString(CryptoJS.enc.Hex);
  };

  const createHmacsha1 = (password, value) => {
    const key = CryptoJS.enc.Utf8.parse(password);
    const content = CryptoJS.enc.Utf8.parse(value);
    return CryptoJS.HmacSHA1(content, key).toString(CryptoJS.enc.Base64);
  };

  const requestObj = {
    domain: 'https://v0.api.upyun.com',
    bucket: '/' + serviceName + '/',
    httpMethod: {
      get: 'GET',
      post: 'POST',
      delete: 'DELETE'
    },
    commonHeaders: (operator, method, path, password, date) => {
      return {
        'Authorization': getSignHeader(operator, method, path, password, date),
        'Date': date
      };
    },
    addFolderHeaders: () => {
      return {
        'folder': 'true'
      };
    },
    getFileListHeaders: () => {
      return {
        'Accept': 'application/json',
      };
    },
    getFileInforHeaders: () => {
      return {
        'X-HTTP-Method-Override': 'HEAD'
      };
    },
    deleteFileHeaders: () => {
      return {
        'x-upyun-async': true
      };
    }
  };

  const getFileSize = (size) => {
    if (size === null || size.length === 0 || size === '0') {
      return '0 Bytes';
    }

    const unitArr = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
    let index = 0;
    const srcsize = Number(size);
    index = Math.floor(Math.log(srcsize) / Math.log(1024));
    let resultSize = srcsize / Math.pow(1024, index);
    if (index !== 0) {
      resultSize = resultSize.toFixed(2);
    }
    return resultSize + ' ' + unitArr[index];
  };

  const formatDate = (dateObject, normalFormat) => {
    let result = '';
    if (dateObject instanceof Date) {
      const Y = dateObject.getFullYear();
      const M = dateObject.getMonth() + 1 < 10 ? '0' + (dateObject.getMonth() + 1) : dateObject.getMonth() + 1;
      const D = dateObject.getDate() < 10 ? '0' + dateObject.getDate() : dateObject.getDate();
      const h = dateObject.getHours() < 10 ? '0' + dateObject.getHours() : dateObject.getHours();
      const m = dateObject.getMinutes() < 10 ? '0' + dateObject.getMinutes() : dateObject.getMinutes();
      const s = dateObject.getSeconds() < 10 ? '0' + dateObject.getSeconds() : dateObject.getSeconds();
      if (normalFormat) {
        result = Y + '-' + M + '-' + D + ' ' + h + ':' + m + ':' + s;
      } else {
        result = Y + M + D + h + m + s;
      }
    }

    return result;
  };

  const getNowTime = () => {
    const nowTime = new Date();
    return formatDate(nowTime, false);
  };

  kintone.events.on(['app.record.index.edit.show', 'app.record.create.show'], function(event) {
    const record = event.record;
    record[config.directory]['disabled'] = true;

    return event;
  });

  kintone.events.on('app.record.detail.show', function(event) {
    const record = event.record;
    const directory = record[config.directory]['value'];

    const div = document.createElement('div');
    const space = kintone.app.record.getSpaceElement(config.fileList);
    let fileListHtml = '<table id="fileList"><tr><th>' + i18n.msg_tableTitle_fileName +
      '</th><th>' + i18n.msg_tableTitle_fileSize +
      '</th><th>' + i18n.msg_tableTitle_fileDate + '</th><th></th></tr>';

    const imageViewerDiv = document.createElement('div');
    const imageViewerSpace = kintone.app.record.getSpaceElement(config.upload);
    const validImageTypes = ['image/gif', 'image/jpeg', 'image/png'];

    const downloadFile = (filePath) => {
      const downloadUrl = config.domainUrl + '/' + filePath + '?_upd=true';
      window.open(downloadUrl);
    };

    const deleteFileFun = (filePath) => {
      kintone.proxy(
        requestObj.domain + requestObj.bucket + filePath,
        requestObj.httpMethod.delete,
        Object.assign(
          requestObj.commonHeaders(
            operatorName,
            requestObj.httpMethod.delete,
            requestObj.bucket + filePath,
            operatorPassword,
            now
          ),
          requestObj.deleteFileHeaders()
        ),
        {}
      ).then(function (response) {
        window.location.reload();
      }).catch(function (error) {
        console.log(error);
      });
    };

    kintone.proxy(
      requestObj.domain + requestObj.bucket + directory,
      requestObj.httpMethod.get,
      Object.assign(
        requestObj.commonHeaders(
          operatorName,
          requestObj.httpMethod.get,
          requestObj.bucket + directory,
          operatorPassword,
          now
        ),
        requestObj.getFileListHeaders()
      ),
      {}
    ).then(function (response) {
      if (response[1] !== 200) {
        swal.fire({
          icon: 'error',
          title: i18n.msg_directory_error
        });
        return event;
      }

      const responseJson = window.JSON.parse(!response[0] ? '{}' : response[0]);
      const files = responseJson.files;
      const imageListDiv = document.createElement('div');
      let countImage = 0;
      imageListDiv.setAttribute('id', 'imageViewer');
      imageListDiv.setAttribute('style', 'display: none');
      for (let i = 0, len = files.length; i < len; i++) {
        let file = files[i];
        fileListHtml += '<tr><td>' + file['name'] +
          '</td><td>' + getFileSize(file['length']) +
          '</td><td>' + formatDate(new Date(file['last_modified'] * 1000), true) +
          '</td><td><button id="downloadFile_' + i + '" class="button">' + i18n.msg_btn_download + '</button>&nbsp;&nbsp;' +
          '<button id="deleteFile_' + i + '" class="button">' + i18n.msg_btn_delete + '</button>' +
          '</td></tr>';
        if (validImageTypes.includes(file['type'])) {
          countImage++;
          imageListDiv.innerHTML += '<div><img src="' + config.domainUrl + '/' + directory + '/' + file['name'] + '" ></div>';
        }
      }
      if (countImage > 0) {
        const imageViewerBtnDiv = document.createElement('div');
        imageViewerBtnDiv.innerHTML += '<button id="openViewer" class="button">' + i18n.msg_btn_imageViewer + '</button>';
        imageViewerDiv.appendChild(imageListDiv);
        imageViewerSpace.appendChild(imageViewerDiv);
        imageViewerSpace.appendChild(imageViewerBtnDiv);
        const viewer = new Viewer(document.getElementById('imageViewer'), {
          url: 'data-original'
        });

        document.getElementById('openViewer').onclick = function () {
          viewer.show();
        };
      }

      div.innerHTML = fileListHtml;
      space.appendChild(div);
      jQuery('[id^=downloadFile_]').click(function (e) {
        const id = e.target.id;
        const filePath = directory + '/' + files[id.slice(id.lastIndexOf('_') + 1)]['name'];
        downloadFile(filePath);
      });
      jQuery('[id^=deleteFile_]').click(function (e) {
        const id = e.target.id;
        const file = directory + '/' + files[id.slice(id.lastIndexOf('_') + 1)]['name'];
        swal.fire({
          title: i18n.msg_alert_delete_title,
          text: i18n.msg_alert_delete_text,
          icon: 'warning',
          showCancelButton: true,
          confirmButtonColor: '#3085d6',
          cancelButtonColor: '#d33',
          confirmButtonText: i18n.msg_alert_delete_confirm,
          cancelButtonText: i18n.msg_alert_delete_cancel
        }).then((result) => {
          if (result.value) {
            deleteFileFun(file);
          }
        });
      });
    }).catch(function (error) {
      console.log(error);
    });

    return event;
  });

  kintone.events.on(['app.record.detail.delete.submit', 'app.record.index.delete.submit'], function (event) {
    const record = event.record;
    const directory = record[config.directory]['value'];

    kintone.proxy(
      requestObj.domain + requestObj.bucket + directory,
      requestObj.httpMethod.get,
      Object.assign(
        requestObj.commonHeaders(
          operatorName,
          requestObj.httpMethod.get,
          requestObj.bucket + directory,
          operatorPassword,
          now
        ),
        requestObj.getFileListHeaders()
      ),
      {}
    ).then(function (response) {
      if (response[1] !== 200) {
        return event;
      }

      const responseJson = window.JSON.parse(!response[0] ? '{}' : response[0]);
      const files = responseJson.files;
      const deleteFileQueue = [];
      for (let i = 0, len = files.length; i < len; i++) {
        let file = files[i]['name'];
        deleteFileQueue.push(
          kintone.proxy(
            requestObj.domain + requestObj.bucket + directory + '/' + file,
            requestObj.httpMethod.delete,
            Object.assign(
              requestObj.commonHeaders(
                operatorName,
                requestObj.httpMethod.delete,
                requestObj.bucket + directory + '/' + file,
                operatorPassword,
                now
              ),
              requestObj.deleteFileHeaders()
            ),
            {}
          ).then(function (response) {
            console.log(response);
          }).catch(function (error) {
            console.log(error);
          })
        );
      }

      Promise.all(deleteFileQueue).then((res) => {
        kintone.proxy(
          requestObj.domain + requestObj.bucket + directory,
          requestObj.httpMethod.delete,
          requestObj.commonHeaders(
            operatorName,
            requestObj.httpMethod.delete,
            requestObj.bucket + directory,
            operatorPassword,
            now
          ),
          {}
        ).then(function (response) {
          console.log(response);
        }).catch(function (error) {
          console.log(error);
        });
      });
    }).catch(function (error) {
      console.log(error);
    });

    return event;
  });

  kintone.events.on('app.record.create.submit', function (event) {
    const record = event.record;
    const appId = kintone.app.getId();
    const loginUser = kintone.getLoginUser();
    record[config.directory]['value'] = appId + '/' + loginUser.name + '/' + getNowTime();

    return event;
  });

  kintone.events.on('app.record.create.submit.success', function (event) {
    const record = event.record;
    const directory = record[config.directory]['value'];

    return new Promise(function (resolve) {
      kintone.proxy(
        requestObj.domain + requestObj.bucket + directory,
        requestObj.httpMethod.post,
        Object.assign(
          requestObj.commonHeaders(
            operatorName,
            requestObj.httpMethod.post,
            requestObj.bucket + directory,
            operatorPassword,
            now
          ),
          requestObj.addFolderHeaders()
        ),
        {}
      ).then(function (response) {
        return resolve(event);
      }).catch(function (error) {
        console.log(error);
      });
    });
  });

  kintone.events.on('app.record.edit.show', function(event) {
    const record = event.record;
    const directory = record[config.directory]['value'];
    record[config.directory]['disabled'] = true;

    const fileListSpace = kintone.app.record.getSpaceElement(config.fileList);
    const fileListdiv = document.createElement('div');
    let fileListHtml = '<table id="fileList"><tr><th>' + i18n.msg_tableTitle_fileName +
      '</th><th>' + i18n.msg_tableTitle_fileSize +
      '</th><th>' + i18n.msg_tableTitle_fileDate + '</th></tr>';

    kintone.proxy(
      requestObj.domain + requestObj.bucket + directory,
      requestObj.httpMethod.get,
      Object.assign(
        requestObj.commonHeaders(
          operatorName,
          requestObj.httpMethod.get,
          requestObj.bucket + directory,
          operatorPassword,
          now
        ),
        requestObj.getFileListHeaders()
      ),
      {}
    ).then(function (response) {
      if (response[1] !== 200) {
        swal.fire({
          icon: 'error',
          title: i18n.msg_directory_error
        });
        return event;
      }

      const uploadSpace = kintone.app.record.getSpaceElement(config.upload);
      const uploadDiv = document.createElement('div');
      uploadDiv.appendChild(attachment.render());
      uploadSpace.appendChild(uploadDiv);
      attachment.setFiles([]);

      const responseJson = window.JSON.parse(!response[0] ? '{}' : response[0]);
      const files = responseJson.files;
      for (let i = 0, len = files.length; i < len; i++) {
        let file = files[i];
        fileListHtml += '<tr><td>' + file['name'] +
          '</td><td>' + getFileSize(file['length']) +
          '</td><td>' + formatDate(new Date(file['last_modified'] * 1000), true) +
          '</td></tr>';
      }
      fileListdiv.innerHTML = fileListHtml;
      fileListSpace.appendChild(fileListdiv);
    }).catch(function (error) {
      console.log(error);
    });

    return event;
  });

  kintone.events.on('app.record.edit.submit', function(event) {
    const record = event.record;
    const files = attachment.getFiles();
    if (files.length <= 0) {
      return event;
    }
    const directory = record[config.directory]['value'];

    return new Promise(function (resolve) {
      kintone.proxy(
        requestObj.domain + requestObj.bucket + directory,
        requestObj.httpMethod.get,
        Object.assign(
          requestObj.commonHeaders(
            operatorName,
            requestObj.httpMethod.get,
            requestObj.bucket + directory,
            operatorPassword,
            now
          ),
          requestObj.getFileListHeaders()
        ),
        {}
      ).then(function (response) {
        if (response[1] !== 200) {
          swal.fire({
            icon: 'error',
            title: i18n.msg_directory_error
          });
          return event;
        }

        if (files.length === 0) {
          return event;
        }

        swal.fire({
          html: '<div id="alertMessage">' + i18n.msg_uploading + '</div><br/><div id="upload"></div>',
          allowOutsideClick: false,
          allowEscapeKey: false,
          showConfirmButton: false,
          width: '500px',
          onOpen: () => {
            swal.showLoading();
          }
        });

        const xhrOnProgress = (fun) => {
          xhrOnProgress.onprogress = fun;
          return function () {
            const xhr = $.ajaxSettings.xhr();
            if (typeof xhrOnProgress.onprogress !== 'function') {
              return xhr;
            }
            if (xhrOnProgress.onprogress && xhr.upload) {
              xhr.upload.onprogress = xhrOnProgress.onprogress;
            }
            return xhr;
          }
        };

        const truncateFileName = (filename) => {
          if (filename.length <= 10) {
            return filename
          }
          return filename.slice(0, 10) + '...'
        };


        const fileUploadQueue = (i) => {
          if (files.length === i) {
            swal.close();
            return resolve(event);
          }
          const fileName = files[i].name;
          const fileSize = files[i].size;
          const fileType = files[i].type;
          const policyStringfy = {
            'bucket': serviceName,
            'save-key': directory + '/' + fileName,
            'expiration': parseInt(Date.parse(new Date()) + 3600),
            'content-type': fileType,
            'content-length': fileSize
          };
          const policy = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(JSON.stringify(policyStringfy)));
          const uploadValue = requestObj.httpMethod.post + '&/' + serviceName + '&' + policy;
          const auth = createHmacsha1(createMd5(operatorPassword), uploadValue);
          const signature = 'UPYUN ' + operatorName + ':' + auth;
          const formData = new FormData();
          formData.append('authorization', signature);
          formData.append('policy', policy);
          formData.append('file', files[i]);
          $.ajax({
            url: requestObj.domain + '/' + serviceName,
            type: requestObj.httpMethod.post,
            data: formData,
            contentType: false,
            processData: false,
            xhr: xhrOnProgress(function (e) {
              const percent = Math.round(e.loaded * 100 / e.total);
              $('#progress' + i).show();
              $('#percent'+ i).text(percent + '%');
              $('#bar' + i).width(percent + '%');
            }),
            beforeSend: function (xhr) {
              const uploadTarget = $('#upload');
              uploadTarget.html(uploadTarget.html() + "<div id='uploadinfor" + i + "' class='uploadInfor'>" +
                truncateFileName(fileName) + "&nbsp;&nbsp;<div id='progress" + i + "' class='uploadProgress'><div id='percent" + i + "' class='uploadPercent'></div><div id='bar" + i + "' class='uploadBar'></div></div></div>"
              );
            },
            success: function () {
              $('#progress' + i).hide();
              $('#uploadinfor' + i).html(truncateFileName(fileName) + '&nbsp;&nbsp;' + i18n.msg_upload_success);
            },
            error: function () {
              $('#progress' + i).hide();
              $('#uploadinfor' + i).html(truncateFileName(fileName) + '&nbsp;&nbsp;' + i18n.msg_upload_failed);
            },
            complete: function() {
              fileUploadQueue(++i);
            }
          });
        };

        fileUploadQueue(0)
      });
    });
  });

})(jQuery, kintone.$PLUGIN_ID);